home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1995 June / MacFormat 25.iso / Shareware City / Developers / GetFileIcon ƒ / GetFileIcon.c next >
Text File  |  1995-01-02  |  14KB  |  608 lines

  1. /*
  2. GetFileIcon.c
  3. 1/2/95
  4. ver 1.0
  5. -------
  6.  
  7.  
  8. GetFileIcon is based on the FindIcon.c code by James Walker.
  9.  
  10. Q: Why does GetFileIcon exist?  Why not use FindIcon?
  11. A: There are several reasons:
  12.     1.    Displaying a file's icon is one of the most intuitive things to do on a
  13.         a Macintosh.  Unfortunately, it is also very difficult; I would estimate
  14.         that there is at least one person a week on the comp.sys.mac.programmer
  15.         newsgroup who asks how to display the icon of a file.  Most programmers
  16.         are usually referred to the FindIcon code by James Walker, but the code only
  17.         shows how to get a files' icon; it doesn’t demonstrate how to display the
  18.         icon.  Several programmers have posted messages requesting further help...
  19.         this snippet is intended to take care of that need.
  20.  
  21.     2.    The FindIcon routines are able to get a file or a folders' icon.
  22.         Personally, I do not need to retrieve a folders' icon, so I took everything
  23.         that pertained to folders out (thus, reducing the amount of code by
  24.         approximately half).
  25.  
  26.     3.    The FindIcon routine is comprised of 13 source files and 14 header files.
  27.         With GetFileIcon, there are only two files to keep track of (GetFileIcon.c
  28.         and GetFileIcon.h).
  29.  
  30.     4.    When I compile my project, I always have strict type checking turned on.
  31.         Since GetFileIcon uses forbid_action() and forbid() in conjunction with
  32.         'gotos', it took quite a bit of tweaking on my part to get the code to work.
  33.  
  34.  
  35.  
  36. Q: How do I use GetFileIcon?
  37. A: Simple, In your THINK C project, make sure you have MacTraps and MacTraps2
  38.     added, then add GetFileIcon.c to the project.  For an example on how to call
  39.     GetFileIcon, look in GetFileIconExample.c.  BTW: This code seems to compile
  40.     fine under THINK C 6.0 -> 7.0.4... I do not know about earlier versions of
  41.     THINK C.
  42.  
  43.  
  44.  
  45. Other useful information:  If you wish to contact me, my Internet address is
  46. jbeeghly@u.washington.edu (at least it is until June '95).  I make no guarantees
  47. over the stability of the code (in other words, use it at your own risk).  If
  48. you want to find out more about getting & plotting a files' icon, I strongly suggest
  49. you get the code to FindIcon (available at most mac development FTP sites) and THINK
  50. Reference.
  51.  
  52.  
  53. */
  54.  
  55.  
  56. #include "GetFileIcon.h"
  57.  
  58.  
  59. /*    ------------------------------------------------------------------
  60.     GetFileIcon        Given a file specification for a file, folder, or
  61.                     volume, create an appropriate icon suite
  62.                     and find its label color.
  63.     ------------------------------------------------------------------ */
  64. pascal OSErr GetFileIcon(
  65. /* --> */    FSSpec                *thing,
  66. /* --> */    IconSelectorValue    iconSelector,
  67. /* <-- */    Handle                *theSuite)
  68. {
  69.     CInfoPBRec        cpb;
  70.     OSErr            err;
  71.  
  72.  
  73.     *theSuite = NULL;
  74.  
  75.  
  76.     if( IsVolEjected(thing->vRefNum) )
  77.     {
  78.         err = volOffLinErr;
  79.     }
  80.     else
  81.     {
  82.         cpb.hFileInfo.ioVRefNum        = thing->vRefNum;
  83.         cpb.hFileInfo.ioDirID        = thing->parID;
  84.         cpb.hFileInfo.ioNamePtr        = thing->name;
  85.         cpb.hFileInfo.ioFDirIndex    = 0;
  86.         err = PBGetCatInfoSync( &cpb );
  87.  
  88.  
  89.         if( !err )
  90.         {
  91.             if( (cpb.hFileInfo.ioFlAttrib & ioDirMask) == 0)    // file
  92.             {
  93.                 if(cpb.hFileInfo.ioFlFndrInfo.fdFlags & kHasCustomIcon)
  94.                 {
  95.                     err = GetCustomFileIcon(thing, iconSelector, theSuite );
  96.                 }
  97.                 else    // no custom icon
  98.                 {
  99.                     err = GetNormalFileIcon(&cpb, iconSelector, theSuite);
  100.                 }
  101.             }
  102.             // ----------- end of normal case --------------
  103.         }    
  104.     }
  105.  
  106.     // ------- error handler ---------
  107.     /*if(thing->parID == fsRtParID)    // a volume
  108.     {
  109.         if(err == volOffLinErr)
  110.         {
  111.             *labelColor = ttOffline;
  112.         }
  113.         err = GetVolumeIcon(thing->vRefNum, iconSelector, theSuite);
  114.     }*/
  115.  
  116.     return( err );
  117. }
  118.  
  119.  
  120. Boolean    IsVolEjected( short vRefNum )
  121. {
  122.     OSErr            err;
  123.     HVolumeParam    vol_pb;
  124.     
  125.     vol_pb.ioNamePtr    = NULL;
  126.     vol_pb.ioVRefNum    = vRefNum;
  127.     vol_pb.ioVolIndex    = 0;
  128.     err = PBHGetVInfoSync( (HParmBlkPtr )&vol_pb );
  129.     
  130.     return( (err == noErr) && (vol_pb.ioVDRefNum > 0) );
  131. }
  132.  
  133.  
  134.  
  135. OSErr    GetCustomFileIcon(
  136. /* --> */    FSSpec                *filespec,
  137. /* --> */    IconSelectorValue    iconSelector,
  138. /* <-- */    Handle                *theSuite)
  139. {
  140.     short    saveResFile, customResFile;
  141.     OSErr    err;
  142.     
  143.     saveResFile = CurResFile();
  144.     SetResLoad( false );
  145.     customResFile = FSpOpenResFile(filespec, fsRdPerm);
  146.  
  147.     SetResLoad( true );
  148.  
  149.     if(customResFile == -1)
  150.     {
  151.         err = ResError();
  152.     }
  153.     else
  154.     {
  155.         err = GetResourceIcons(theSuite, kCustomIconResource, iconSelector);
  156.         if( !err )
  157.         {
  158.             if( IsSuiteEmpty( *theSuite ) )
  159.             {
  160.                 err = GetResourceIcons(theSuite, kVolumeAliasIconResource, iconSelector);
  161.             }
  162.         }
  163.  
  164.         CloseResFile( customResFile );
  165.         UseResFile( saveResFile );
  166.     }
  167.     return( err );
  168. }
  169.  
  170.  
  171. OSErr    GetNormalFileIcon(
  172. /* --> */    CInfoPBRec            *cpb,
  173. /* --> */    IconSelectorValue    iconSelector,
  174. /* <-- */    Handle                *theSuite)
  175. {
  176.     OSErr            err;
  177.     long            dataSize;
  178.     Handle            iconData;
  179.     Byte            iconType;
  180.     GetIconData        getData;
  181.     short            iconID;
  182.     Boolean            inFinder;
  183.     short            saveResFile, FinderResFile, sysVRefNum;
  184.     long            sysDirID;
  185.  
  186.  
  187.  
  188.     iconID = FindGenericIconID(cpb->hFileInfo.ioFlFndrInfo.fdType, &inFinder );
  189.     saveResFile = CurResFile();
  190.  
  191.  
  192.     if( inFinder )
  193.     {
  194.         //(void) FindFolder( kOnSystemDisk, kSystemFolderType,
  195.         //      kDontCreateFolder, &sys_vRefNum, &sys_dirID );
  196.         FindFolder(kOnSystemDisk, kSystemFolderType, kDontCreateFolder, &sysVRefNum, &sysDirID);
  197.  
  198.         SetResLoad( false );
  199.         FinderResFile = HOpenResFile(sysVRefNum, sysDirID, "\pFinder", fsRdPerm);
  200.         SetResLoad( true );
  201.  
  202.         if(FinderResFile == -1)
  203.         {
  204.             err = ResError();
  205.         }
  206.         else
  207.         {
  208.             err = GetResourceIcons(theSuite, iconID, iconSelector);
  209.             CloseResFile( FinderResFile );
  210.         }
  211.     }
  212.     else    // icons in desktop DB or in System
  213.     {
  214.         getData.DTRefNum = FindDesktopDatabase(cpb->dirInfo.ioVRefNum,
  215.             cpb->hFileInfo.ioFlFndrInfo.fdCreator );
  216.  
  217.         if(getData.DTRefNum != 0)    // the right icons are in some desktop
  218.         {
  219.             err = NewIconSuite( theSuite );
  220.             if( !err )
  221.             {
  222.                 getData.fileCreator    = cpb->hFileInfo.ioFlFndrInfo.fdCreator;
  223.                 getData.fileType    = cpb->hFileInfo.ioFlFndrInfo.fdType;
  224.                 if(getData.fileType == kApplicationAliasType)
  225.                 {
  226.                     getData.fileType = 'APPL';
  227.                 }
  228.                 err = ForEachIconDo(*theSuite, iconSelector, GetIconProc, &getData);
  229.             }
  230.         }
  231.         if( (getData.DTRefNum == 0) || IsSuiteEmpty( *theSuite ) )
  232.         {
  233.             UseResFile( 0 );
  234.             err = GetResourceIcons(theSuite, iconID, iconSelector);
  235.         }
  236.     }
  237.  
  238.     UseResFile( saveResFile );
  239.  
  240.     return( err );
  241. }
  242.  
  243.  
  244.  
  245. /*    ------------------------------------------------------------------
  246.     GetIcon        This is an IconAction procedure to fill in one
  247.                     slot of an icon suite, given a file type, creator,
  248.                     and desktop database.
  249.     ------------------------------------------------------------------ */
  250. static    pascal OSErr GetIconProc(ResType theType, Handle *theIcon, void *yourDataPtr)
  251. {
  252.     OSErr            err;
  253.     GetIconData        *data;
  254.     DTPBRec            deskRec;
  255.  
  256.     err = noErr;
  257.     data = (GetIconData *)yourDataPtr;
  258.  
  259.     *theIcon = NewHandle( kLarge8BitIconSize );
  260.  
  261.  
  262.  
  263.     //require_action( *theIcon, NewHandle, err = memFullErr );
  264.  
  265.     if( !(*theIcon) )
  266.     {
  267.         err = memFullErr;
  268.     }
  269.     else
  270.     {
  271.         HLock( *theIcon );
  272.     
  273.         deskRec.ioDTRefNum        = data->DTRefNum;
  274.         deskRec.ioDTBuffer        = **theIcon;
  275.         deskRec.ioDTReqCount    = kLarge8BitIconSize;
  276.         deskRec.ioFileCreator    = data->fileCreator;
  277.         deskRec.ioFileType        = data->fileType;
  278.     
  279.         switch( theType )
  280.         {
  281.             case large1BitMask:
  282.                 deskRec.ioIconType = kLargeIcon;
  283.                 break;
  284.     
  285.             case large4BitData:
  286.                 deskRec.ioIconType = kLarge4BitIcon;
  287.                 break;
  288.     
  289.             case large8BitData:
  290.                 deskRec.ioIconType = kLarge8BitIcon;
  291.                 break;
  292.     
  293.             case small1BitMask:
  294.                 deskRec.ioIconType = kSmallIcon;
  295.                 break;
  296.     
  297.             case small4BitData:
  298.                 deskRec.ioIconType = kSmall4BitIcon;
  299.                 break;
  300.     
  301.             case small8BitData:
  302.                 deskRec.ioIconType = kSmall8BitIcon;
  303.                 break;
  304.             
  305.             default:
  306.                 // The desktop database does not have "mini" icons
  307.                 deskRec.ioIconType = 1000;
  308.                 break;
  309.         }
  310.     
  311.     
  312.         err = PBDTGetIconSync( &deskRec );
  313.     
  314.         if(err == noErr)
  315.         {
  316.             HUnlock( *theIcon );
  317.             SetHandleSize(*theIcon, deskRec.ioDTActCount);
  318.         }
  319.         else
  320.         {
  321.             DisposeHandle( *theIcon );
  322.             *theIcon = NULL;
  323.             err = noErr;
  324.         }
  325.         
  326.     }
  327.     return( err );
  328. }
  329.  
  330.  
  331. /*    ------------------------------------------------------------------
  332.     Find_desktop_database            Find the reference number of a
  333.                                     desktop database containing icons
  334.                                     for a specified creator code.
  335.     The search begins on a specified volume, but covers all volumes.
  336.     ------------------------------------------------------------------ */
  337. static    short    FindDesktopDatabase(
  338. /* --> */    short    firstVRefNum,
  339. /* --> */    OSType    fileCreator)    // returns a DT refnum or 0
  340. {
  341.     OSErr            err;
  342.     VolumeParam        vpb;
  343.     short            DTRefNum;
  344.  
  345.     DTRefNum = 0;
  346.  
  347.     if(!InOneDesktop(firstVRefNum, fileCreator, &DTRefNum))
  348.     {
  349.         vpb.ioNamePtr = NULL;
  350.         for(vpb.ioVolIndex = 1; PBGetVInfoSync((ParmBlkPtr )&vpb) == noErr; ++vpb.ioVolIndex)
  351.         {
  352.             if(vpb.ioVRefNum == firstVRefNum)
  353.                 continue;
  354.             if( InOneDesktop(vpb.ioVRefNum, fileCreator, &DTRefNum) )
  355.                 break;
  356.         }
  357.     }
  358.     
  359.     return( DTRefNum );
  360. }
  361.  
  362.  
  363.  
  364. /*    ------------------------------------------------------------------
  365.     InOneDesktop            Determine whether the desktop database for
  366.                             one particular volume contains icons for
  367.                             a given creator code, and if so, return its
  368.                             reference number.
  369.     ------------------------------------------------------------------
  370. */
  371. static    Boolean    InOneDesktop(
  372. /* --> */    short    vRefNum,
  373. /* --> */    OSType    fileCreator,
  374. /* <-- */    short    *dtRefNum)
  375. {
  376.     OSErr        err;
  377.     DTPBRec        deskRec;
  378.     Boolean        retVal;
  379.     
  380.     retVal = false;    // default to failure
  381.     deskRec.ioNamePtr = NULL;
  382.     deskRec.ioVRefNum = vRefNum;
  383.     err = PBDTGetPath( &deskRec );
  384.  
  385.  
  386.     if( !err )
  387.     {
  388.         /*    We want to ignore any non-icon data, such as the 'paul'
  389.             item that is used for drag-and-drop. */
  390.     
  391.         deskRec.ioFileCreator = fileCreator;
  392.         deskRec.ioIndex = 1;
  393.         do
  394.         {
  395.             deskRec.ioTagInfo = 0;
  396.             err = PBDTGetIconInfoSync( &deskRec );
  397.             deskRec.ioIndex += 1;
  398.         }while( (err == noErr) && (deskRec.ioIconType <= 0) );
  399.     
  400.         if(err == noErr)
  401.         {
  402.             retVal = true;
  403.             *dtRefNum = deskRec.ioDTRefNum;
  404.         }
  405.     }
  406.     return( retVal );
  407. }
  408.  
  409.  
  410. pascal OSErr GetResourceIcons(
  411. /* <-- */    Handle    *theSuite,
  412. /* --> */    short    theID,
  413. /* --> */    long    theSelector)
  414. {
  415.     OSErr    err;
  416.     
  417.     err = Get1IconSuite(theSuite, theID, theSelector);
  418.     if(err == noErr)
  419.     {
  420.         err = CopyEachIcon( *theSuite );
  421.     }
  422.  
  423.     return( err );
  424. }
  425.  
  426.  
  427.  
  428. OSErr CopyEachIcon(
  429. /* <-> */    Handle theSuite)
  430. {
  431.     return( ForEachIconDo(theSuite, svAllAvailableData, CopyOneIcon, NULL) );
  432. }
  433.  
  434.  
  435. static pascal OSErr CopyOneIcon(
  436. /* --> */    ResType        theType,
  437. /* <-> */    Handle        *theIcon,
  438. /* --- */    void        *yourDataPtr)
  439. {
  440.     OSErr    err;
  441.     
  442.     if(*theIcon != NULL)
  443.     {
  444.         LoadResource( *theIcon );
  445.         err = HandToHand( theIcon );
  446.         if(err != noErr)
  447.             *theIcon = NULL;
  448.     }
  449.     
  450.     return( noErr );
  451. }
  452.  
  453.  
  454. short    FindGenericIconID(
  455. /* --> */    OSType theType,
  456. /* <-- */    Boolean    *inFinder)
  457. {
  458.     short        id;
  459.     register     OSType *iconTypes;
  460.     register    short *iconIDs;
  461.     Ptr            iconIDsStart;
  462.     OSType        *beginSysIcons;
  463.     
  464.     asm {
  465.         BRA        @start
  466.     @icon_type_storage
  467.         dc.L    'ifil'
  468.         dc.L    'sfil'
  469.         dc.L    'ffil'
  470.         dc.L    'tfil'
  471.         dc.L    'kfil'
  472.         dc.L    'FFIL'
  473.         dc.L    'DFIL'
  474.     @Finder_icons_end
  475.         dc.L    kContainerFolderAliasType
  476.         dc.L    kContainerTrashAliasType
  477.         dc.L    kSystemFolderAliasType
  478.         dc.L    'INIT'
  479.         dc.L    'APPL'
  480.         dc.L    'dfil'
  481.         dc.L    'pref'
  482.         dc.L    kAppleMenuFolderAliasType
  483.         dc.L    kControlPanelFolderAliasType
  484.         dc.L    kExtensionFolderAliasType
  485.         dc.L    kPreferencesFolderAliasType
  486.         dc.L    kStartupFolderAliasType
  487.         dc.L    kApplicationAliasType
  488.         dc.L    kExportedFolderAliasType
  489.         dc.L    kDropFolderAliasType
  490.         dc.L    kSharedFolderAliasType
  491.         dc.L    kMountedFolderAliasType
  492.     @icon_id_storage
  493.         dc.W    12500
  494.         dc.W    14000
  495.         dc.W    14500
  496.         dc.W    14501
  497.         dc.W    14750
  498.         dc.W    15500
  499.         dc.W    15750
  500.  
  501.         dc.W    genericFolderIconResource
  502.         dc.W    trashIconResource
  503.         dc.W    systemFolderIconResource
  504.         dc.W    genericExtensionIconResource
  505.         dc.W    genericApplicationIconResource
  506.         dc.W    genericDeskAccessoryIconResource
  507.         dc.W    genericPreferencesIconResource
  508.         dc.W    appleMenuFolderIconResource
  509.         dc.W    controlPanelFolderIconResource
  510.         dc.W    extensionsFolderIconResource
  511.         dc.W    preferencesFolderIconResource
  512.         dc.W    startupFolderIconResource
  513.         dc.W    genericApplicationIconResource
  514.         dc.W    ownedFolderIconResource
  515.         dc.W    dropFolderIconResource
  516.         dc.W    sharedFolderIconResource
  517.         dc.W    mountedFolderIconResource
  518.     @start
  519.         LEA        @icon_type_storage, iconTypes
  520.         LEA        @icon_id_storage, iconIDs
  521.         LEA        @Finder_icons_end, A0
  522.         move.L    A0, beginSysIcons
  523.     }
  524.     
  525.     iconIDsStart = (Ptr )iconIDs;
  526.     id = genericDocumentIconResource;    // default
  527.     
  528.     while( ((Ptr )iconTypes) < iconIDsStart)
  529.     {
  530.         if(theType == *iconTypes)
  531.         {
  532.             id = *iconIDs;
  533.             break;
  534.         }
  535.         iconTypes++;
  536.         iconIDs++;
  537.     }
  538.  
  539.     *inFinder = (iconTypes < beginSysIcons);
  540.  
  541.     return( id );
  542. }
  543.  
  544.  
  545.  
  546. /*    --------------------------------------------------------------------
  547.     Get1IconSuite            Like GetIconSuite, but only looks in
  548.                             the current resource file.
  549.     
  550.     In case you're wondering why it would be necessary to ensure that
  551.     icons come from only one file, suppose you're looking at a
  552.     file that has its custom icon bit set, but for some reason does
  553.     not contain a custom icon, or at least not a full family.
  554.     Way down the resource chain, there may be another file, say a
  555.     font file, that does have a full family of custom icons. 
  556.     So you get an unexpected icon.
  557.     -------------------------------------------------------------------- */
  558.  
  559. pascal OSErr Get1IconSuite(
  560. /* <-- */    Handle    *theSuite,
  561. /* --> */    short    theID,
  562. /* --> */    long    theSelector)
  563. {
  564.     OSErr        err;
  565.  
  566.     err = NewIconSuite( theSuite );
  567.     if( !err )
  568.     {
  569.         err = ForEachIconDo(*theSuite, theSelector,
  570.             (IconAction ) Get1Icon, &theID);
  571.     }
  572.     return( err );
  573. }
  574.  
  575.  
  576.  
  577. static pascal OSErr Get1Icon(
  578. /* --> */    ResType    theType,
  579. /* <-> */    Handle    *theIcon,
  580. /* --> */    short    *resID)
  581. {
  582.     *theIcon = Get1Resource(theType, *resID);
  583.  
  584.     return( noErr );
  585. }
  586.  
  587.  
  588. static pascal OSErr TestHandle(ResType theType, Handle *theIcon, void *yourDataPtr)
  589. {
  590.     if(*theIcon != NULL)
  591.         *(Boolean *)yourDataPtr = false;    // not empty!
  592.  
  593.     return( noErr );
  594. }
  595.  
  596.  
  597. Boolean IsSuiteEmpty( Handle theSuite )
  598. {
  599.     Boolean        retVal;
  600.     
  601.     retVal = true;
  602.     ForEachIconDo(theSuite, svAllAvailableData, TestHandle, &retVal);
  603.  
  604.     return( retVal );
  605. }
  606.  
  607.  
  608.